package com.cdn.client.netty.client;

import com.cdn.client.domain.vo.NodeResourceVO;
import com.cdn.client.netty.handler.ClientHandler;
import com.cdn.client.netty.utils.NodeResourceUtil;
import com.cdn.client.netty.utils.RpcProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Component
public class NettyClient {
    @Autowired
    private RpcProperties rpcProperties;

    @Autowired
    private NodeResourceUtil nodeResourceUtil;

//    private final String host = rpcProperties.getEndpoints();  // 服务器地址
//    private final int port = rpcProperties.getPort();           // 服务器端口
//    private final Long nodeId = rpcProperties.getNodeId();      // 该客户端节点ID
    private Channel channel;
    private boolean isConnected = false;

    private EventLoopGroup group;
    private Bootstrap bootstrap;
    private ScheduledExecutorService heartBeatExecutor;

    // 在应用启动时启动客户端并连接到服务器
    public void start() throws InterruptedException {
        if (isConnected) {
            return;  // 如果已经连接，直接返回
        }

        System.out.println(rpcProperties.getEndpoints()[0]);

        group = new NioEventLoopGroup();  // 创建 EventLoopGroup
        bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)  // 使用 NIO Socket
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringDecoder());  // 解码器
                        ch.pipeline().addLast(new StringEncoder());  // 编码器
                        ch.pipeline().addLast(new ClientHandler());  // 自定义的消息处理器
                    }
                });

        try {
            // 连接到服务器
            ChannelFuture channelFuture = bootstrap
                    .connect(rpcProperties.getEndpoints()[0], rpcProperties.getPort()).sync();
            channel = channelFuture.channel();
            isConnected = true;  // 标记为已连接
            System.out.println("客户端已连接到服务器");
            // 启动定时任务
            startReportingNodeStatus();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException("客户端连接失败", ex);
        }
    }

    // 获取已连接的 Channel
    public Channel getChannel() {
        if (!isConnected) {
            throw new IllegalStateException("客户端未连接");
        }
        return channel;
    }

    // 在应用关闭时关闭客户端连接
    @PreDestroy
    public void shutdown() {
        if (isConnected) {
            // 关闭定时任务
            if (heartBeatExecutor != null) {
                heartBeatExecutor.shutdownNow();
            }

            // 关闭 Netty 连接
            group.shutdownGracefully();  // 优雅地关闭 EventLoopGroup
            System.out.println("客户端连接已关闭");
        }
    }

    // 定时上报节点状态信息
    private void startReportingNodeStatus() {
        heartBeatExecutor = Executors.newSingleThreadScheduledExecutor();
        heartBeatExecutor.scheduleAtFixedRate(() -> {
            if (isConnected) {
                NodeResourceVO status = getNodeStatus();
                try {
                    // 使用 JSON 格式发送节点状态信息
                    ObjectMapper objectMapper = new ObjectMapper();
                    String jsonStatus = objectMapper.writeValueAsString(status);
                    channel.writeAndFlush(jsonStatus);
                    System.out.println("已发送节点状态信息: " + jsonStatus);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 0, 10, TimeUnit.SECONDS);  // 每 10 秒发送一次状态信息
    }

    // 获取节点的状态信息
    private NodeResourceVO getNodeStatus() {
        NodeResourceVO status = new NodeResourceVO();
        status.setNodeId(rpcProperties.getNodeId());

        // 获取 CPU 使用率
        BigDecimal cpuUsage = nodeResourceUtil.getCpuUsage();
        status.setCpu(cpuUsage);  // 将 CPU 使用率设置到状态中

        // 获取内存使用情况
        BigDecimal memoryUsage = nodeResourceUtil.getMemoryUsage();
        status.setMemory(memoryUsage);  // 将内存使用情况设置到状态中

        // 获取下行带宽
        Long downstreamBandwidth = nodeResourceUtil.getDownstreamBandwidth();
        status.setDownstreamBandwidth(downstreamBandwidth);  // 将下行带宽设置到状态中

        // 获取连接数
        Integer connectionCount = nodeResourceUtil.getConnectionCount();
        status.setConnections(connectionCount);  // 将连接数设置到状态中

        // 获取系统负载
        BigDecimal systemLoad = nodeResourceUtil.getSystemLoad();
        status.setLoad(systemLoad);  // 将系统负载设置到状态中

        return status;
    }


}
